package mechgtk_gui;

use strict;
use warnings;

use Glib qw( TRUE FALSE );

use threads;
use threads::shared;

use LWP::Simple;
use WWW::Mechanize;
use HTML::TokeParser;

use Glib qw/TRUE FALSE/;
use Gtk2 qw/-init -threads-init/;
use Gtk2::GladeXML;
use Switch;

Glib::Object->set_threadsafe (TRUE);

#Declare our Work Messages
use constant C_MSG_NONE				=> 0;
use constant C_MSG_TEST				=> 1;
use constant C_MSG_LOGIN			=> 2;
use constant C_MSG_DL_LINKS			=> 3;

#Declare constants
use constant C_BORDER_WIDTH			=> 2;
use constant C_LIST_CONTROL_W		=> 500;
use constant C_LIST_CONTROL_H		=> 150;
use constant C_FILENAME_COL_MAX_W	=> 350;

#Declare our columns
use constant C_FILENAME				=> 0;
use constant C_PROGRESS				=> 1;

#Declare Text constants
use constant C_TXT_FILENAME_COLUMN	=> "Filename";
use constant C_TXT_PROGRESS_COLUMN	=> "Progress";

#Create Shared Variables
my @work_queue;
share(@work_queue); #will work for first level keys
my $die : shared = 0;

#thread
my $thread;

#Downloader Variables
###############
# Global Variables
###############
my %user_settings = (); 
my $login_url = 'http://account.mp3sparks.com/login.shtml?logging=on';
my $list_url = 'http://account.mp3sparks.com/mylinks.shtml';

my $login = '';
my $password = '';

#Mp3 data
my $final_mp3_data = undef;
my $cur_mp3_size = undef;
my $total_mp3_size = undef;

my $agent = WWW::Mechanize->new();

my $treeview_progress;
my $iter;
my $list_store;


sub run
{
	my $self = shift->new();
	Gtk2->main();
}

sub new
{
	return bless ({}, shift)->_init(); 
}

sub _init
{
	my $self = shift;
	my $glade_file = __FILE__;
	$glade_file =~ s/gnab_gui.pm/gnab.glade/;
	my $gui = Gtk2::GladeXML->new($glade_file);
	
	$gui->signal_autoconnect_from_package( $self );

	#Get treeview_progress
	my $v_view_status = $gui->get_widget("v_view_status");
	
	my $label_status = $gui->get_widget("label_status");
	
	$thread = threads->new(\&work, $label_status, $v_view_status);
		
	return $self;
}

sub on_main_window_delete_event
{
	print "don't tase me bro\n";
	$die = 1;
	$thread->join;
	Gtk2->main_quit();
}

sub on_button_login_clicked
{
	#my $crap = shift;
	#my $gui = shift;
	print "login clicked\n";
   	push(@work_queue, C_MSG_LOGIN);
#   	push(@work_queue, C_MSG_DL_LINKS);
	#my $v_view_status = $gui->get_widget("treeview");
	#$v_view_status->login();
}

#########################################################
sub work{
    
    my ( $label_status, $v_view_status ) = @_;
    $|++;
    my $work_msg; 
    
    my %dl_hash;
    
   	$list_store = Gtk2::ListStore->new(qw/Glib::String Glib::Int/);
    
    #Create List
	$treeview_progress = Gtk2::TreeView->new_with_model( $list_store );
    
	#Create List Filename Column
	my $list_filename_column = Gtk2::TreeViewColumn->new();
	$list_filename_column->set_title( C_TXT_FILENAME_COLUMN );
	
	#Create List Filename Column Renderer
	my $list_filename_column_renderer = Gtk2::CellRendererText->new();
	
	#Pack Renderer
	$list_filename_column->pack_start( $list_filename_column_renderer, FALSE );
	
	#Set Attributes
	$list_filename_column->set_attributes
		( 
		$list_filename_column_renderer,
		'text' => C_FILENAME 
		);
		
	$list_filename_column->set_expand( TRUE );
	$list_filename_column->set_resizable( TRUE );
	
	#Append Filename column to list
	$treeview_progress->append_column( $list_filename_column );    

	#Create List Progress Column
	my $list_progress_column = Gtk2::TreeViewColumn->new();
	$list_progress_column->set_title( C_TXT_PROGRESS_COLUMN );
	
	#Create List Progress Column Renderer
	my $list_progress_column_renderer = Gtk2::CellRendererProgress->new();
	
	#Pack Renderer
	$list_progress_column->pack_start( $list_progress_column_renderer, TRUE );
	
	#Set Attributes
	$list_progress_column->set_attributes
		( 
		$list_progress_column_renderer,
		'value' => C_PROGRESS 
		);
	
	$list_progress_column->set_expand( TRUE );
	$list_progress_column->set_resizable( TRUE );
	
	#Append Filename column to list
	$treeview_progress->append_column( $list_progress_column );

    #Place into Vbox View Status
	$v_view_status->pack_start( $treeview_progress, TRUE, TRUE, C_BORDER_WIDTH );
    
    $v_view_status->show_all();
    
    while(TRUE)
    {
       	#Do we need to kill the thread?
		if($die == 1)
		{ 
			destroy_objects_on_die();
			#return
			return 
		};
		
		#Do we have anything in the work queue?
		if(@work_queue)
		{
			#get next work message
    		$work_msg = shift @work_queue;
			
		switch ( $work_msg ) 
			{
			case C_MSG_LOGIN
				{ 
				print "Login..\n";	
				mp3sparks_login($login, $password, $agent);
				my @dl_links = mp3sparks_dl_links($agent);
				
				if(@dl_links)
					{	
					$label_status->set_label( mp3sparks_parse_filename($dl_links[0]) );
					}
					
				foreach( @dl_links )
					{
					$dl_hash{ $_ } = add_item( mp3sparks_parse_filename($_), 0, $list_store );
					}
				
				}

			case C_MSG_DL_LINKS
				{
				print "DL Links...\n";

				foreach my $key (keys %dl_hash) 
					{
     				print "$key\n";
     				$iter = $dl_hash{ $key };
     				mp3sparks_fetch_mp3( $key );
					}
				}

			else		
				{ 
				print "Case not true\n"; 
				}
			}

		}
			
		#Sleep! Dont kill the cpu
        Glib::Idle->add(
         	sub	{
              	if($die == 1)
	              	{ 
	              	destroy_objects_on_die();
	              	return; 
	              	};
	              	
               	return FALSE;
               	});
                
       	select(undef,undef,undef, .1);
				
    }
}


###############
# Subroutines
###############

# Name: destroy_objects_on_die
# Param:
# Return:
# Desc: Destroy all Gtk objects on thread exit
sub destroy_objects_on_die
{
	$treeview_progress->destroy();
} #destroy_objects_on_die


# Name: mp3sparks_login
# Param: $login, $password, $agent
# Return: $agent
# Desc: Logins agent into mp3sparks account
sub mp3sparks_login
{
	#get params
	my ( $login, $password, $agent ) = @_;
	$agent->get( $login_url );

	#Submit login information
	print "Logging in...\n";
	$agent->submit_form
		(
		form_number => 1,
		form_name => 'AUTENTIFICATION',
		fields => 	{ 	
			login => $login,
			password => $password
				} 
		);

	return $agent;
} # mp3sparks_login #


# Name: mp3sparks_dl_links
# Param: $agent
# Return: @dl_links
# Desc: Gets MP3 Download Links
sub mp3sparks_dl_links
{
	#get params
	my ( $agent ) = @_;

	print "Getting links...\n";

	#Get Download links list
	$agent->get( $list_url );

	#Get all links
	my @dl_links_data = $agent->links();

	#Get URL information from each link datum
	my @dl_links;
	foreach( @dl_links_data )
		{;
		push( @dl_links, $_->url() );
		}

	return @dl_links;

} # mp3sparks_dl_links

# Name: mp3sparks_parse_filename
# Param: $link
# Return: $mp3_filename
# Desc: Gets MP3 filename
sub mp3sparks_parse_filename
{
	#get params
	my ( $link ) = @_;

	print "Getting Mp3 filename...\n";
	
	$link =~ /\/.*\/(.*\..*)/;

	my $mp3_filename = $1;

	return $mp3_filename;
}

# Name: mp3sparks_fetch_mp3
# Param: $iter
# Return: 
# Desc: Fetches Mp3 and writes it to disk
sub mp3sparks_fetch_mp3
{
	#get params
	my ( $link, $iter, $list_store ) = @_;

	print "Fetching Mp3...\n";

	my $mp3_data = mp3sparks_dl_mp3( $link );
	my $mp3_filename = mp3sparks_parse_filename( $link );
	mp3sparks_write_mp3_file( $mp3_data, $mp3_filename );

} #mp3sparks_fetch_mp3

# Name: mp3sparks_write_mp3_file
# Param: $mp3_data, $filename
# Return: 
# Desc: Writes MP3 to filename
sub mp3sparks_write_mp3_file
{
	#get params
	my ( $mp3_data, $filename ) = @_;

	print "Writing Mp3 file...\n";
	
	open( FILE, ">$filename" );
	print FILE $mp3_data;
	close( FILE );
} #mp3sparks_write_mp3_file

# Name: mp3sparks_dl_mp3
# Param: $link
# Return: $mp3_data
# Desc: Gets MP3 data
sub mp3sparks_dl_mp3
{
	#get params
	my ( $link ) = @_;

	print "Getting Mp3 Data...\n";

	my $ua = LWP::UserAgent->new();
	my $res = $ua->head( $link );
	$total_mp3_size = $res->headers->content_length;
		
	#reset cur mp3 size
	$cur_mp3_size = 0;

	my $response = $ua->get($link, ':content_cb' => \&mp3sparks_dl_mp3_callback, );

	#newline for progress bar
	print "\n";

	return $final_mp3_data;
}

# Name: mp3sparks_dl_mp3_callback
# Param: $data, $response, $protocol
# Return: $mp3_data
# Desc: Callback function
sub mp3sparks_dl_mp3_callback 
{
	my ($data, $response, $protocol) = @_;
   	$final_mp3_data .= $data;
	
	#add size of $data to cur_mp3_size
	$cur_mp3_size += length $data;

	my $percentage = ( $cur_mp3_size / $total_mp3_size ) * 100;

	$list_store->set ($iter, C_PROGRESS, $percentage );

#	$bar->update($cur_mp3_size);

} #mp3sparks_dl_mp3_callback

sub add_item 
{
my ($filename, $progress, $list_store) = @_;

my $iter = $list_store->append;

$list_store->set 
	(
	$iter,
	C_FILENAME, $filename,
	C_PROGRESS, $progress
	);

return $iter;
} # add_item

1;